#include"common.h"

/*create a socket to listen*/
int socket_create(const char* ip,const int port)  //创建一个监听套接字
{
	if((NULL==ip) || (port<0))
	{
		//print_log()
		return -1;
	}

    //socket() – Create endpoint for communication
    //int socket ( int family, int type, int protocol);
    //创建socket用PF，bind/connect用AF。
    //结果一个PF只有一个AF，从来没有过例外，所以就混用了。
	int sock=socket(AF_INET,SOCK_STREAM,0);

	//检验是否成功创建socket
	if(sock<0)
	{
		//print_log();
		return -1;
	}

	int op=1;

	//setsockopt(), Allow an application to set a socket option
	//int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
	//如果想要在套接字级别上设置选项，就必须把level设置为SOL_SOCKET
    //一般来说，一个端口释放后会等待两分钟之后才能再被使用，SO_REUSEADDR是让端口释放后立即就可以被再次使用。
    //optval：    指针，指向存放选项值的缓冲区。
    //optlen：    optval缓冲区的长度。
	setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&op,sizeof(op));

	//声明sockaddr_in 类型的结构体 local
	/*
	struct sockaddr_in {
    unsigned short sin_family; //address family (always AF_INET)
    unsigned short sin_port; // port num in network byte order
    struct in_addr sin_addr; //IP addr in network byte order
    unsigned char sin_zero[8]; // pad to sizeof(struct sockaddr)
    };
	*/

	/*
	◼ htonl: host byte order → network byte order for long int
    ◼ htons: host byte order → network byte order for short int
    ◼ ntohl: network byte order → host byte order for long int
    ◼ ntohs: network byte order → host byte order for short int
	*/

	/*
	typedef uint32_t in_addr_t;
	struct in_addr {
    in_addr_t s_addr;
    };
	*/

	struct sockaddr_in local;
	local.sin_family=AF_INET;
	local.sin_port=htons(port);
	local.sin_addr.s_addr=inet_addr(ip);//Converts an IP address in numbers-and-dots notation into unsigned long in network byte order

    //Bind (sockfd, (struct sockaddr *)&serv , sizeof(serv));
    //Must cast Internet-specific socket address (sockaddr_in *) to generic socket address (sockaddr *) for connect, bind, and accept
    //将一本地地址与一套接口捆绑。

	if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0)
	{
		//print_log();
		return -1;
	}

    //Waiting for someone to connect to my port
    //listen(Sock-fd, QueueLen);
    // place a socket in passive mode and make it ready to accept incoming connections
	if(listen(sock,5)<0)
	{
		//print_log();
		return -1;
	}

	//if the client connect this ip, port, it will listen and return the server socket.
	return sock;
}


int socket_accept(int sock)     //接受连接 pass in the sock listening
{
	struct sockaddr_in peer;
	socklen_t len=sizeof(peer);

    //accept() – Receive a call
    //Get a socket descriptor for an incoming connection
    //The server calls accept() to extract the next incoming request
    //accept() fills in the structure (sockaddr) with the IP address and
    //protocol port number of the remote machine
    // addr用于存放客户端的地址，addrlen在调用函数时被设置为addr指向区域的长度
	int connfd=accept(sock,(struct sockaddr*)&peer,&len);
	if(connfd<0)
	{
		//print_log()
		return -1;
	}
	return connfd;
}

int socket_connect(const char* ip,const int port)   //连接远端主机，这里传入的参数都是主机字节序
{
	if((NULL==ip) || (port<0))
	{
		//print_log()
		return -1;
	}
	
	int sock=socket(AF_INET,SOCK_STREAM,0);
	if(sock<0)
	{
		//print_log()
		return -1;
	}

	struct sockaddr_in peer;
	peer.sin_family=AF_INET;
	peer.sin_port=htons(port);
	peer.sin_addr.s_addr=inet_addr(ip);
//	int connect (int sockfd, const struct sockaddr *servaddr , socklen_t addrlen );
	if(connect(sock,(struct sockaddr*)&peer,sizeof(peer))<0)
	{
		//print_log()
		return -1;
	}
	return sock;
}

int recv_data(int sock,char* buf,int bufsize)  //从sock读取数据
{
	memset(buf,0,bufsize);//清空
	ssize_t s=recv(sock,buf,bufsize,0);//读取
	if(s<=0)//判断
		return -1;
	return s;
}

int send_response(int sock,int code)   //发送响应码到sock
{
	int stat_code=htonl(code);//字节序转换 主机字节序转换为网络字节序， 网络字节序为大端，大端就是整数的高位字节存放在内存的低地址处。
	/*
	#include <sys/socket.h>
    ssize_t send (int sockfd, const void *buff, size_t nbytes, int flags);
    sockfd: socket descriptor you want to send data to.
    buff: The address of the data to be sent
    nbytes: The number of bytes to be sent
    flags: The flag controlling the connection, usually 0
	*/
	if(send(sock,&stat_code,sizeof(stat_code),0)<0)
	{
		//print_log()
		return -1;
	}
	return 0;
}

void read_input(char *buf,int buffsize)  //从标准输入读取一行
{
	memset(buf,0,buffsize);
	if(NULL!=fgets(buf,buffsize,stdin))
	{
		char *n=strchr(buf,'\n');
		if(n)
			*n='\0';
	}
}

void trimstr(char* str,int n)   //去除字符串中的空白和换行
{
	int i=0;
	for(i=0;i<n;i++)
	{
		if(isspace(str[i])||('\0'==str[i]))
			str[i]=0;
	}
}










